# -*- ecoding: utf-8 -*-
# @ModuleName: 多策略资金曲线计算K
# @Author: wk
# @Email: 306178200@qq.com
# @Time: 2024/2/25 16:25
import pandas as pd
from Config import *
from Evaluate import *

# 将实盘策略的strategy_list拷贝过来即可
strategy_list = [
        {
            "strategy": "Strategy_TradeNumMeanV999",  # 策略名称。与strategy目录中的策略文件名保持一致。
            "offset_list": [0],  # 根据自己回测来决定。offset_list 配置错误，会影响选币和下单金额
            "cap_weight": 1,  # 资金权重。程序会自动根据这个权重计算你的策略占比，具体可以看1.8的直播讲解
            "is_use_spot": True,  # 是否使用现货交易
        },
        {
            "strategy": "Strategy_longbbi",  # 策略名称。与strategy目录中的策略文件名保持一致。
            "offset_list": [0],  # 根据自己回测来决定。offset_list 配置错误，会影响选币和下单金额
            "cap_weight": 2,  # 资金权重。程序会自动根据这个权重计算你的策略占比，具体可以看1.8的直播讲解
            "is_use_spot": True,  # 是否使用现货交易
        },
    ]



filepath_list = []
cap_weight_list = []
for strategy in strategy_list:
    Strategy = __import__('strategy.%s' % strategy['strategy'], fromlist=('',))
    # 从Strategy中获取需要回测持仓周期
    hold_period = Strategy.hold_period
    # 获取Strategy的文件名
    stg_name = Strategy.stg_name
    for offset in strategy["offset_list"]:
        # 判断是否使用现货。如果使用现货，之后保存的文件名中带有SPOT；如果不使用现货，则为SWAP
        if strategy['is_use_spot']:
            label = 'SPOT'
        else:
            label = 'SWAP'
        if not os.path.exists(os.path.join(back_test_path,f'{stg_name}_{label}_资金曲线_{hold_period}_{offset}.csv')):
            print(f"资金曲线: {stg_name}_{label}_资金曲线_{hold_period}_{offset}.csv 不存在！！！\n请运行 {strategy['strategy']}, offset={offset}的回测")
            exit()
        filepath_list.append(f'{stg_name}_{label}_资金曲线_{hold_period}_{offset}.csv')
        cap_weight_list.append(strategy['cap_weight'])

all_equity_df = pd.DataFrame()  # 定义空的资金曲线df
rtn_list = []  # 所有offset策略评价集合
sorted_stg_tag = {}  # 用于图表的offset排序
# 遍历所有offset资金曲线
for idx,_filepath in enumerate(filepath_list):

    cap_weight = cap_weight_list[idx]
    for i in range(cap_weight):
        stg_tag = _filepath.replace('.csv', '')  # 从文件名称中解析出offset
        if i>0:
            stg_tag = stg_tag + '###' + str(i)
        # 读取资金曲线文件
        _df = pd.read_csv(back_test_path + _filepath, encoding='gbk', parse_dates=['candle_begin_time'])
        _df = _df[['candle_begin_time', '涨跌幅', '多空资金曲线', '多空调仓比例', '是否爆仓']]  # 获取指定字段
        _df.rename(columns={'涨跌幅': f'涨跌幅_{stg_tag}', '多空资金曲线': f'多空资金曲线_{stg_tag}',
                            '多空调仓比例': f'多空调仓比例_{stg_tag}', '是否爆仓': f'是否爆仓_{stg_tag}'}, inplace=True)

        # 将各个offset资金曲线合并到all_equity_df中
        if all_equity_df.empty:  # 数据为空，直接拷贝读取的资金曲线文件即可
            all_equity_df = _df.copy()
        else:  # 当前已经存在资金曲线，则将新offset资金曲线合并到all_equity_df中
            all_equity_df = pd.merge(left=all_equity_df, right=_df, on='candle_begin_time', how='outer')

        if '###' in stg_tag:
            continue
        # 策略评价
        _df['本周期多空涨跌幅'] = _df[f'涨跌幅_{stg_tag}']
        _df['多空资金曲线'] = _df[f'多空资金曲线_{stg_tag}']
        _df['涨跌幅'] = _df[f'涨跌幅_{stg_tag}']
        _df['多空调仓比例'] = _df[f'多空调仓比例_{stg_tag}']
        _df['是否爆仓'] = _df[f'是否爆仓_{stg_tag}']
        rtn, _, __ = strategy_evaluate(_df)
        rtn = rtn.T
        rtn['stg_tag'] = stg_tag
        rtn_list.append(rtn)
        sorted_stg_tag[f'多空资金曲线_{stg_tag}'] = _df.iloc[-1]['多空资金曲线']

# 合并每个offset的策略评价信息
rtn_df = pd.concat(rtn_list, ignore_index=True)
rtn_df.set_index('stg_tag', inplace=True)
rtn_df.sort_values('累积净值', ascending=False, inplace=True)
print(rtn_df.to_markdown())  # 输出各个offset策略评价信息

# 重新排序
all_equity_df.sort_values('candle_begin_time', inplace=True)
all_equity_df.reset_index(inplace=True, drop=True)

# 对空的涨跌幅填充0
pct_cols = [_ for _ in all_equity_df.columns if '涨跌幅' in _]
all_equity_df.loc[:, pct_cols] = all_equity_df[pct_cols].fillna(value=0)

# 对空的资金曲线填充1
equity_cols = [_ for _ in all_equity_df.columns if '多空资金曲线' in _]
all_equity_df.loc[:, equity_cols] = all_equity_df[equity_cols].fillna(value=1)

# 获取多空调仓比例的列名
turnover_cols = [_ for _ in all_equity_df.columns if '多空调仓比例' in _]

# 获取是否爆仓的列名
warehouse_cols = [_ for _ in all_equity_df.columns if '是否爆仓' in _]

# 计算所有offset的均值，获取账户总的净值资金曲线
all_equity_df['多空资金曲线'] = all_equity_df[equity_cols].mean(axis=1)
# 计算账户涨跌幅，通过账户净值反推
all_equity_df['本周期多空涨跌幅'] = pd.DataFrame([1] + all_equity_df['多空资金曲线'].to_list()).pct_change()[0].iloc[
                                    1:].to_list()
all_equity_df['涨跌幅'] = all_equity_df['本周期多空涨跌幅']
# 计算周期平均多空调仓比例
all_equity_df['多空调仓比例'] = all_equity_df[turnover_cols].mean(axis=1)
all_equity_df['是否爆仓'] = all_equity_df[warehouse_cols].sum(axis=1)
save_path = os.path.join(back_test_path, f'多策略多空资金曲线.csv')
all_equity_df.to_csv(save_path, encoding='gbk', index=False)

# 对所有offset资金曲线进行评价
rtn, year_return, month_return = strategy_evaluate(all_equity_df)
save_path = os.path.join(back_test_path, f'多策略策略评价.csv')
rtn.to_csv(save_path, encoding='gbk')
print('\n\n所有策略综合策略评价\n', rtn, '\n\n所有策略综合分年收益率：\n', year_return,
      '\n\n所有策略综合分月收益率：\n', month_return)

# =====画图
BTC = pd.read_csv(swap_path + 'BTC-USDT.csv', encoding='gbk', parse_dates=['candle_begin_time'], skiprows=1)
BTC['BTC涨跌幅'] = BTC['close'].pct_change()
all_equity_df = pd.merge(left=all_equity_df, right=BTC[['candle_begin_time', 'BTC涨跌幅']], on=['candle_begin_time'],
                         how='left')
all_equity_df['BTC涨跌幅'].fillna(value=0, inplace=True)
all_equity_df['BTC资金曲线'] = (all_equity_df['BTC涨跌幅'] + 1).cumprod()

ETH = pd.read_csv(swap_path + 'ETH-USDT.csv', encoding='gbk', parse_dates=['candle_begin_time'], skiprows=1)
ETH['ETH涨跌幅'] = ETH['close'].pct_change()
all_equity_df = pd.merge(left=all_equity_df, right=ETH[['candle_begin_time', 'ETH涨跌幅']], on=['candle_begin_time'], how='left')
all_equity_df['ETH涨跌幅'].fillna(value=0, inplace=True)
all_equity_df['ETH资金曲线'] = (all_equity_df['ETH涨跌幅'] + 1).cumprod()

# 生成画图数据字典，可以画出所有offset资金曲线以及各个offset资金曲线
data_dict = {'多策略多资金权重综合资金曲线': '多空资金曲线', 'BTC资金曲线': 'BTC资金曲线','ETH资金曲线': 'ETH资金曲线'}
# 对各个offset的表现，按照净值进行从大到小排序
sorted_stg_tag = sorted(sorted_stg_tag.items(), key=lambda d: d[1], reverse=True)
# 遍历所有offset字段，将各个offset资金曲线的数据进行配置，方便后面画图
for col, v in sorted_stg_tag:
    data_dict['策略_' + col.split('_')[1] +'_' +col.split('_')[-1]] = col
pic_title = '多策略多资金权重综合资金曲线 nv:%s_pro:%s_risk:%s' % (
rtn.at['累积净值', 0], rtn.at['年化收益', 0], rtn.at['最大回撤', 0])
# 调用画图函数
draw_equity_curve_plotly(all_equity_df, data_dict=data_dict, date_col='candle_begin_time',
                         right_axis={'多空最大回撤': '多空dd2here'},
                         title=pic_title)
